package exo1;

import exo1.exeption.EmptyException;
import exo1.exeption.FullException;
import exo1.exeption.OutOfBoundException;
import exo1.iterator.GenericPileIterator;
import exo1.iterator.MyIterable;
import exo1.iterator.MyIterator;
public class GenericPile<T> implements Checked,MyIterable{

	protected final int MAX_TAILLE;
	protected Object []tab;
	protected int index=0;
	protected int lock=0;
	
	public GenericPile() {
		this(10);
	}
	public GenericPile(int taille) {
		MAX_TAILLE=taille;
		tab=new Object[MAX_TAILLE];
	}
	public void pushSafe(T i) throws FullException{
		if(isFull())
			throw new FullException("la pile est pliene,impossible d'empiler !!");
		push(i);
	}
	public void push(T i){
		invariant();
		assert !isFull():"la pile est pliene,impossible d'empiler !!";
		tab[index]=i;
		index++;
		invariant();
	}
	public int lenght(){
		return index;
	}
	public T popSafe() throws EmptyException {
		if(isEmpty())
			throw new EmptyException("impossible de depiler une pile vide");
			return pop();
		
	}
	public T pop(){invariant();
		assert !isEmpty():"impossible de depiler une pile vide";
		try{
			@SuppressWarnings("unchecked")
			T res= (T) tab[index];
			index--;
			return res;
		}finally{
			invariant();
		}
	}
	@SuppressWarnings("unchecked")
	public T peekSafe() throws EmptyException{ 
		if(isEmpty())
		throw new EmptyException("impossible de depiler une pile vide");
			return peek();
	}
	@SuppressWarnings("unchecked")
	public T peek(){ invariant();
	assert !isEmpty():"impossible de retourner le sommet  une pile vide";
	try{
		return (T) tab[index-1];
	}finally{
		invariant();
	}
}
	public boolean isFull() {
		return (index==MAX_TAILLE)?true:false;
	}

	public boolean isEmpty() {
		return (index==0)?true:false;
	}
	
	public T getSafe(int i) throws OutOfBoundException{
		if(i>=MAX_TAILLE)
			throw new OutOfBoundException("accès hors limite !!");
		return get(i);
	}
	@SuppressWarnings("unchecked")
	public T get(int i){invariant();
		assert(i<MAX_TAILLE):"i>=Max_Tailler Erreur";
		 try{
			 return (T) tab[i];
		 }finally{
			 invariant();
		 }
	}
	public void invariant(){
		try{
			if(lock++!=0)return;
			assert index<=MAX_TAILLE:"index plus grande que la taille de tableau";
			assert index>=0:"index est négative";
		}finally{
			--lock;
		}
	}
	@Override
	public String toString() {
		String s="[";
		int i=0;
		for(i=0;i<index-1;i++){
			s+=tab[i]+",";
		}
		if(index!=0)
		s+=tab[i];
		return s+"]";
	}
	public static void main(String[] args) {
		try { // vérification du test d'assertion
			assert false;
			throw new RuntimeException("JVM option '-ea'");
			}catch (AssertionError e){}
		
			GenericPile<String> pile=new GenericPile<String>(2);
			assert"[]".equals(pile.toString()):pile;
			
			assert pile.isEmpty():"pile est vide";
			assert !pile.isFull():"Pile est pliene";
			try {
				pile.pushSafe("abde");
				pile.pushSafe("zero");
			} catch (FullException e1) {
				e1.printStackTrace();
			}
			assert"[abde,zero]".equals(pile.toString()):pile;
			assert !pile.isEmpty():"pile est vide";
			//Tester les itéerateurs
		     MyIterator<String>i=pile.createIterator();
		     String aux[]={"abde","zero"};
		     int j=0;
		     for(;i.isDone();i.next()){
		    	 System.out.println(">>>"+i.current());
		    	 assert (aux[j++].equals(i.current())):i.current();
		     }
			
			System.out.println("Test unitaire validé");
	}
	public MyIterator<T> createIterator() {
		GenericPileIterator<T> it=new GenericPileIterator<T>(this);
		return it;
	}


}
